#include <process.h>

#include <windows.h>

#include "lib.h"

#include "patch.h"
#include "admin.h"
#include "admpipe.h"
#include "log.h"

//
// TODO!  handle shutdown gracefully (don't shutdown server until admin gone)
//		  secure access to pipe & pipe operations
//

Admin::Admin()
{
	hStopEvt = hThread = (HANDLE)0;

	pipe = new AdminPipe();
	if (!pipe)
		return;
	if (pipe->create() && pipe->initOk())
		pipe->ready();

	hStopEvt = CreateEvent(NULL, TRUE, FALSE, NULL);
	if (!hStopEvt)
		return;
	
	if (!start())
		Log::msgError("Admin::Admin failed.");
}

Admin::~Admin()
{
	stop();

	if (hStopEvt)
	{
		CloseHandle(hStopEvt);
		hStopEvt = (HANDLE)0;
	}

	delete pipe;
	pipe = (AdminPipe*)0;
}

bool8
Admin::initOk()
{
	return (bool8)(0 != (pipe && pipe->initOk() && hStopEvt && hThread));
}

bool8
Admin::start()
{
	DWORD threadID;

	hThread = (HANDLE)_beginthreadex(
		(void*)0, 0, (unsigned(__stdcall*)(void*))threadProc,
		(void*)this, 0, (unsigned*)&threadID);

	return (bool8)(hThread != (HANDLE)0);
}

void
Admin::shutdown()
{
	if (hStopEvt)
		SetEvent(hStopEvt);
}

void
Admin::stop()
{
	if (hThread)
	{
		if (hStopEvt)
			SetEvent(hStopEvt);

		if (WAIT_TIMEOUT == WaitForSingleObject(hThread, 10000))
		{
			Log::msgError("Admin::stop:  WaitFor(workers) failed  ");
			TerminateThread(hThread, 0);
			hThread = (HANDLE)0;
		}

		CloseHandle(hThread);
		hThread = (HANDLE)0;
	}
}

uint32 __stdcall
Admin::threadProc(Admin* This)
{
	DWORD	result;
	HANDLE	events[2];
	bool8	isRunning = true;

	events[0] = This->hStopEvt;
	events[1] = This->pipe->getEvent();

	while (isRunning)
	{
		result = WaitForMultipleObjects(2, events, FALSE, INFINITE);

		switch (result)
		{
			case WAIT_OBJECT_0:		// stopEvt
				isRunning = false;
				break;

			case WAIT_OBJECT_0 + 1:	// pipe io
				if (!This->pipe->processIO())
				{
					Log::msgError("Admin::threadProc:  io failed");
					isRunning = false;
				}
				break;

			default:
				Log::msgError("Admin::threadProc:  wait failed (result: 0x%08x"
					"  error: %ld)  ", result, GetLastError());
				break;
		}
	}

	_endthreadex(0);
	return 0;
}
